package event;


import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import Entities.*;
import Segments.Segment;

public class CarStart extends Event {

    /*
     * A continuaci�n se presentan las variables de la versi�n secuencial
     */
    int EMPTY = -1;
    int newEvent = EMPTY; //verificar porque aqui tenia antes empty
    double evaluatedPosition;
    double deltaT;
    double deltaP;
    double arrivalPosition;
    double arrivalTime;
    double startTime;
    double PosibledeltaT;
    double PosibledeltaP;
    double PosiblearrivalPosition;
    double PosiblearrivalTime;
    Event nextEvent;
    int VERDE = 1;
    int ROJO = 0;
    int AMBAR = 3;
  
    /*
     * Fin de variables de version secuencial
     */
    Event root;
    Segment segment;
    static String N = System.getProperty("line.separator");
  
    private boolean LOG = true;

    public CarStart() {

    }
    //debo recibir segment tambien
    public CarStart(Segment segment) {


        this.root = segment.getRoot();
        this.segment = segment;


    }

  
    @Override
    public void run() {
        boolean log = false;
       
 myLogger.debug("Executing At: " + this.evTime() + " event type:  " + this.getEventType());

        //segment.agregarEvento(this.getTime()+5, 2, objectId, eventPosition+segment.getSize());


        //Escribir el evento ejecutado en un archivo

        try {
            FileOutputStream out = new FileOutputStream("c:/temp/log.txt", true);

            PrintWriter miArchivo = new PrintWriter(out);
            miArchivo.write(this.objectId() + ",");
            miArchivo.write(this.evTime() + ",");
            miArchivo.write(segment.getId() + ",");
            miArchivo.write(this.evPosition() + ",");
            miArchivo.write(this.getEventType() + ",");

            miArchivo.println();
            miArchivo.close();
        } catch (IOException ioe) {
            //System.out.println("Error en la creaci�n del archivo log.txt");
            throw new UnsupportedOperationException("The output file log cant be created !!");
        }


// la creaci[on del carro va en el modulo creador de veh[iculos
        //por ahorita que se quede aqui., en agregarevento en segmento si es cararrival le pongo el id al evento.



        Car car = (Car) objectId;



        nextEvent = root.siguiente;
        // Obtengo el primer evento en la FEL (SQS) de este segmento.

        evaluatedPosition = segment.getSize();

        while (nextEvent != root) {



            if (nextEvent.getEventType() != LCE && nextEvent.getLane() == getLane()) // No es un cambio de luz.
            {
                if (nextEvent.evPosition() <= evaluatedPosition) {

                    if (nextEvent.evPosition() > this.evPosition()) {

                        if (nextEvent.getEventType() == BE || nextEvent.getEventType() == WBE || nextEvent.getEventType() == CE) {
                            if (log) {
                                System.out.println("Estoy viendo un " + nextEvent.getEventType() + "a las " + nextEvent.evTime());
                            }
                            /*
                             * Las unidades de LA VELOCIDAD (standard velocity)
                             * esta dada en metros por hora, y los resultados
                             * son en segundos
                             */
                            arrivalPosition = nextEvent.evPosition() - car.getDisMinSafe();
                            deltaP = arrivalPosition - this.evPosition();
                            deltaT = (deltaP * 3600) / car.getVelocity();
                            arrivalTime = deltaT + evTime();

                            /*
                             * aqui hay dos casos para cuando llego despues de la hora del evento que estoy analizando
                             * o llego antes.
                             * si llego despues se supone que el evento que estoy analizando ya paso, asi que no me importa si fue un stop
                             * real o de warning, asi que pongo un stop tipo warning para analizar
                             * Si llego antes de que suceda el evento, verifico que tipo de stop es y tomo decisiones.
                             */
                            if (arrivalTime >= nextEvent.evTime()) {
                                // Posiblemente cuando llegue al punto de colision, el otro
                                //  vehiculo ya se fue por eso es solo un warning.
                                newEvent = WSE;
                                startTime = arrivalTime;


                            } else {


                                if (nextEvent.getEventType() == BE) { // se el de adelante esta parado por mucho tiempo,
                                    // entonces el vehiculo en cuestion debera pararse y arrancar hasta un tiempo delay despues.
                                    startTime = nextEvent.evTime() + car.getDelayToStart();//ESTO ES PARA SIMULAR EL RETARDO DE ARRANQUE DE UN CONDUCTOR QUE REALMENTE PARO
                                    newEvent = SE;
                                } else {    // en el caso de que el vehiculo de adelante posiblemente heredo el stop del de adelante. solo hacemos warnings.
                                    // puedes ser WBE o CE
                                    startTime = nextEvent.evTime();
                                    newEvent = WSE;
                                }

                            }
                            evaluatedPosition = nextEvent.evPosition();
                        }

                    }
                }
            } else // es un cambio de luz
            {
                // Se elimina el car.getDisMinSafe(), para que evalue el tiempo que tarda en llegar
                // al extremo de la calle ya que al parecer no encontro ningun obstaculo.

                PosiblearrivalPosition = nextEvent.evPosition();
                PosibledeltaP = PosiblearrivalPosition - this.evPosition();

                PosibledeltaT = (PosibledeltaP * 3600) / car.getVelocity();

                //Si el evento start viene por un stop de verdad, entonces
                // el carrito deber� arrancar, por lo tanto, debemos tomar en cuenta ese tiempo
                if (this.getEventType() == BE) {//ya que los wbe no tienen delay, ya que solo se despiertan para ver pero no se detienen.
                    PosiblearrivalTime = PosibledeltaT + evTime() + car.getDelayToStart();
                } else {
                    PosiblearrivalTime = PosibledeltaT + evTime();
                }

                // esto es para un arrival PosiblearrivalTime = PosibledeltaT + evTime();
                //aqui no se necesita un delaytostart pues cuando el coche lllega
                //no se programa el arranque

                if (newEvent == EMPTY) // en caso de que el simulador, ya habia definido algun evento con algun elemento de la lista previamente visitado o no
                {
                    if (PosiblearrivalTime < nextEvent.evTime())//SI EL VEHICULO LLEGA ANTES DEL EVENTO
                    {
                        if (nextEvent.getDesiredStatus() == VERDE) {
                            //DEBE ESTAR PARADO ESE TIEMPO HASTA QUE SE PONGA EN VERDE.
                            newEvent = SE;
                            arrivalPosition = PosiblearrivalPosition - car.getDisMinSafe();
                            deltaP = arrivalPosition - this.evPosition();
                            deltaT = (deltaP * 3600) / car.getVelocity();
                            arrivalTime = deltaT + evTime();
                            startTime = nextEvent.evTime() + car.getDelayToStart(); //LE agrego delay porque el vehiculo arranca delay unidades despues de que el semaforo se puso en verde
                        } else {
                            if (nextEvent.getDesiredStatus() == ROJO) {
                                newEvent = CE;
                                arrivalPosition = PosiblearrivalPosition;
                                deltaP = PosibledeltaP;
                                deltaT = PosibledeltaT;
                                arrivalTime = deltaT + evTime();
                                startTime = arrivalTime;//SI ESTOY EN UN EVENTO DE ARRIVAL
                            //NO OCUPO DELAYTOSTART, PERO SI ESTOY EN UN STOP, SI OCUPO EL DELAYTYOSTART
                            //evaluatedPosition = arrivalPosition;
                            } else {


                                //2/feb/07 ELN ya no lo vamos a ignorar, se agrega el codigo
                                if (nextEvent.getDesiredStatus() == AMBAR) {
                                    newEvent = CE;
                                    arrivalPosition = PosiblearrivalPosition;
                                    deltaP = PosibledeltaP;
                                    deltaT = PosibledeltaT;
                                    arrivalTime = deltaT + evTime();
                                    startTime = arrivalTime;//SI ESTOY EN UN EVENTO DE ARRIVAL
                                //NO OCUPO DELAYTOSTART, PERO SI ESTOY EN UN STOP, SI OCUPO EL DELAYTYOSTART
                                //evaluatedPosition = arrivalPosition;
                                }

                            }
                        }
                    } else //SI EL VEHICULO LLEGA DESPUES DEL EVENTO.
                    {
                        if (nextEvent.getDesiredStatus() == VERDE) {
                            newEvent = CE;
                            arrivalPosition = PosiblearrivalPosition;
                            deltaP = PosibledeltaP;
                            deltaT = PosibledeltaT;
                            arrivalTime = deltaT + evTime();
                            startTime = arrivalTime;
                        //evaluatedPosition = arrivalPosition;
                        } else {
                            if (nextEvent.getDesiredStatus() == ROJO) {
                                /*SE AGREGA EL TIPO DE EVENTO WE (WARNING EVENT)
                                 * PARA REPRESENTAR LOS STOPS QUE SON SOLO DE ALERTA Y NO
                                 * PROVOCA EN EL AUTOMOVIL QUE SE PARE REALMENTE
                                 * */
                                newEvent = SE;

                                //AQUI NO PONGO STARTTIME, PORQUE COMO ES STOP NO SE CUANDO VAYA A ACABAR EL STOP.
                                // porque llego y y me paro e inicio en ese momento para ver que voy a hacer.
                                // es que no se cuando va a acabar el stop.
                                arrivalPosition = PosiblearrivalPosition - car.getDisMinSafe();
                                deltaP = arrivalPosition - this.evPosition();
                                deltaT = (deltaP * 3600) / car.getVelocity();
                                arrivalTime = deltaT + evTime();
                                startTime = arrivalTime;
                            //evaluatedPosition = arrivalPosition;
                            } else {
                                //ignorarlo es amariollo
									/*
                                 * 2/FEB/06 eln. AQUI SE agrega el bloque para tomar encuenta al ambar.
                                 */
                                newEvent = CE;
                                arrivalPosition = PosiblearrivalPosition;
                                deltaP = PosibledeltaP;
                                deltaT = PosibledeltaT;
                                arrivalTime = deltaT + evTime();
                                startTime = arrivalTime;
                            //evaluatedPosition = arrivalPosition;

                            }
                        }
                    }
                } else //SI YA SE HABIA DEFINIDO UN EVENTO A EJECUTAR POR EL VEHICULO
                {

                    if (newEvent == CE) {
                        // Si el arrival time del evento que ya tengo predefinido es menor al evento que estoy viendo
                        if (PosiblearrivalTime > nextEvent.evTime()) {
                            //aqui a la mejor podria verificar si voy a llegar a un verde o rojo,
                            // aqui estoy suponiendo es rojo oks.

                            /*calcular a que hora cruzaria si es que cruza AQUI
                             * NO DEBE CRUZAR YA QUE HAY UN STOP EN EL SIGUIENTE*/

                            if (nextEvent.getDesiredStatus() == ROJO) {
                                // Si el estado deseado del siguiente evento es rojo que pase a un stop event y si es un ambar no hace nada, lo
                                //sigue dejando en CE.

                                arrivalPosition = nextEvent.evPosition() - car.getDisMinSafe();
                                deltaP = arrivalPosition - this.evPosition();
                                deltaT = (deltaP * 3600) / car.getVelocity();
                                arrivalTime = deltaT + evTime();
                                startTime = arrivalTime;
                                //evaluatedPosition = arrivalPosition;
                                newEvent = SE;//es stop porque estoy llegando despues del rojo
                            }
                        }
                    } else {
                        if ((newEvent == SE))// Solo nos interesa el stop, ya que los warnings no se deben suplantar por algun otro evento, por eso quitamos todos los warnings de esta comparaci�n
                        {
                            /*
                             *
                             */
                            if (PosiblearrivalTime > nextEvent.evTime()) {

                                /*
                                 *07/feb/07 eln. para que coloque el ce solo cuando el sem�foro sea ambar
                                 *o verde.
                                 */
                                if (nextEvent.getDesiredStatus() == VERDE || nextEvent.getDesiredStatus() == AMBAR) {
                                    arrivalPosition = nextEvent.evPosition();
                                    deltaP = arrivalPosition - this.evPosition();
                                    deltaT = (deltaP * 3600) / car.getVelocity();
                                    arrivalTime = deltaT + evTime();
                                    if (newEvent == SE)//zaz 130207
                                    {
                                        startTime = arrivalTime + car.getDelayToStart();
                                    } else {
                                        startTime = arrivalTime;
                                    }
                                    //	evaluatedPosition = arrivalPosition;
                                    newEvent = CE;
                                }
                            } else { // El vehiculo llegar� antes que se de el evento de cambio de luz
                                //zaz 130207 agrego codigo para que no se quede trabado en el WSE hasta que se pone rojo y entonces avanza
                                if (startTime < PosiblearrivalTime) { // el vehiculo hiba a arrancar antes de que llegara a la posici�n del semaforo?
                                    /// if es verde o ambar
                                    if (nextEvent.getDesiredStatus() == ROJO || nextEvent.getDesiredStatus() == AMBAR) {
                                        arrivalPosition = nextEvent.evPosition();
                                        deltaP = arrivalPosition - this.evPosition();
                                        deltaT = (deltaP * 3600) / car.getVelocity();
                                        arrivalTime = deltaT + evTime();
                                        if (newEvent == SE)//zaz 130207
                                        {
                                            startTime = arrivalTime + car.getDelayToStart();
                                        } else {
                                            startTime = arrivalTime;
                                        }
                                        //	evaluatedPosition = arrivalPosition;
                                        newEvent = CE;
                                    } else {
                                        startTime = nextEvent.evTime();
                                    }
                                /*else
                                startTime = nextEvent.evTime();*/
                                }
                            }
                        }
                    }
                }//Else no es empty

            }//ELSE cambio de luz
            nextEvent = nextEvent.siguiente;
        }


        if (newEvent == EMPTY) {
            // aqui tambien una opcion para seleccionar inter size o street size.

            arrivalPosition = segment.getSize();
            deltaP = arrivalPosition - this.evPosition();
            deltaT = (deltaP * 3600) / car.getVelocity();
            arrivalTime = deltaT + evTime();

            car.setTypeSeq(CE);
            car.setBegEvTime(evTime());
            car.setEndEvTime(arrivalTime);
            car.setCrossDeltaP(deltaP);
            car.setStopTime(arrivalTime);

            startTime = arrivalTime;
            newEvent = CE;

        }
        if (newEvent == CE && !this.segment.isPozo()) //Ojo esta es otra condici�n que es unica para un arrival.
        {
            // falta que compare si es interseccion o calle, por default ahorita dice que llega solo a calles.
            // posiblemente algo como sigue:
                            /*
             */
         /*   Segment segmentOut = null;
            if (segment instanceof Street) {
                Street street = (Street) segment;
                segmentOut = street.getOut();

            }
            if (segment instanceof Intersection) {
                Intersection intersection = (Intersection) segment;
                segmentOut = intersection.randomOut();

            }


*/

           // if (segmentOut.isFull(startTime)) {
            if(false){
                if (LOG) {
                  //  System.out.println("El car" + car.getId() + "vio que el segmento de salida " + segmentOut.getId() + "Esta lleno para el instante " + startTime);
                }

                newEvent = WSE;
                arrivalPosition = segment.getSize() - car.getDisMinSafe();
                deltaP = arrivalPosition - this.evPosition();
                deltaT = (deltaP * 3600) / car.getVelocity();
                arrivalTime = deltaT + this.evTime();
                startTime = arrivalTime;

                if (LOG) {
                    System.out.println(car.getId() + " coloco un  Warning Stop Event, ya que hiba a cruzar pero estaba lleno");
                }


            } else {

                car.setTypeSeq(CE);
                car.setBegEvTime(evTime());
                car.setEndEvTime(arrivalTime);
                car.setCrossDeltaP(deltaP);
                car.setStopTime(arrivalTime);

                this.myStreetControllerAgent.putEvent(this.segment.getId(), arrivalTime, CE, car, arrivalPosition, AMBAR, this.lane);
//segment.agregarEvento(arrivalTime,CE,car,arrivalPosition,3,this.lane); //leavelink
                this.myStreetControllerAgent.putEvent(this.segment.getConnections(), startTime, ALE, car, 0.0, AMBAR, this.lane);
//segmentOut.agregarEvento(startTime,ALE,car,0.0,3,this.lane); // agrega el evento en el segmento siguiente



            }//else not is full
        }// new event not empty

        if ((newEvent == CE) && this.segment.isPozo())// La calle en la que estoy es un pozo.
        {

            arrivalPosition = segment.getSize();
            deltaP = arrivalPosition - this.evPosition();

            deltaT = (deltaP * 3600) / car.getVelocity();

            arrivalTime = deltaT + evTime();




            car.setTypeSeq(CE);
            car.setBegEvTime(evTime());
            car.setEndEvTime(arrivalTime);
            car.setCrossDeltaP(deltaP);
            car.setStopTime(arrivalTime);


            startTime = arrivalTime;

            this.myStreetControllerAgent.putEvent(this.segment.getId(), arrivalTime, CE, car, arrivalPosition, 4, this.lane);
        //segment.agregarEvento(arrivalTime,CE,car,arrivalPosition,4,this.lane); //leavelink
        // new CarLeaveLink().schedule(arrivalTime,CE,objectId(),arrivalPosition,segmentoPrioritario,segmentoPrioritario);






        }
        if (newEvent == SE || newEvent == WSE) {
            if (newEvent == SE) //car.typeSeq =SE;
            {
                car.setTypeSeq(SE);
            } else //car.typeSeq =WSE;
            {
                car.setTypeSeq(WSE);
            }

            car.setBegEvTime(evTime());
            car.setEndEvTime(startTime);
            car.setStopDeltaP(deltaP);
            car.setStopTime(arrivalTime);

            if (newEvent == SE) {
                this.myStreetControllerAgent.putEvent(this.segment.getId(), arrivalTime, SE, car, arrivalPosition, AMBAR, this.lane);
                this.myStreetControllerAgent.putEvent(this.segment.getId(), startTime, BE, car, arrivalPosition, AMBAR, this.lane);

            //     segment.agregarEvento(arrivalTime,SE,car,arrivalPosition,3,this.lane); //CarStop
            //	segment.agregarEvento(startTime,BE,car,arrivalPosition,3,this.lane); //CarStart

            // new CarStop().schedule(arrivalTime,SE,objectId(),arrivalPosition,segmentoPrioritario,segmentoPrioritario);
            //  new CarStart().schedule(startTime,BE,objectId(),arrivalPosition,segmentoPrioritario,segmentoPrioritario);


            } else {
                this.myStreetControllerAgent.putEvent(this.segment.getId(), arrivalTime, WSE, car, arrivalPosition, AMBAR, this.lane);
                this.myStreetControllerAgent.putEvent(this.segment.getId(), startTime, WBE, car, arrivalPosition, AMBAR, this.lane);

            //segment.agregarEvento(arrivalTime,WSE,car,arrivalPosition,3,this.lane); //CarStop
            //segment.agregarEvento(startTime,WBE,car,arrivalPosition,3,this.lane); //CarStart

            //new CarStop().schedule(arrivalTime,WSE,objectId(),arrivalPosition,segmentoPrioritario,segmentoPrioritario);
            //new CarStart().schedule(startTime,WBE,objectId(),arrivalPosition,segmentoPrioritario,segmentoPrioritario);


            }



        }


 myLogger.debug("Finishing At: " + this.evTime() + " event type:  " + this.getEventType());

        myStreetControllerAgent.setReady();
       

    }

    @Override
    public String toString() {
        return "CarStart";

    }

   
}
